#include "EventScheduler.h"

NAMESPACE_BEGIN
double EventScheduler::getCurTime()
{
	return ens_clock.getCurTime();
}

void EventScheduler::scheduleEvent(const Event& new_event)
{
	{
		std::lock_guard<std::mutex> lock(this->event_queue_mtx);
		this->event_queue.push(new_event);
	}
	this->cv.notify_all();
}

void EventScheduler::processEvent()
{
	while (this->if_running)
	{
		std::unique_lock<std::mutex> lock(this->event_queue_mtx);
		this->cv.wait(lock, [&]() {return !this->if_running || !this->event_queue.empty(); });
		std::vector<Event> ready_events;
		while (!this->event_queue.empty() && this->event_queue.top().getExecuteTime() <= this->getCurTime())
		{
			ready_events.push_back(this->event_queue.top());
			this->event_queue.pop();
		}
		lock.unlock();
		for (auto& cur_event : ready_events)
		{
			cur_event.execute();
		}
		lock.lock();
		if (this->event_queue.empty())
		{
			this->cv_event_queue_empty.notify_all();
		}
	}
}

void EventScheduler::stop()
{
	{
		std::lock_guard<std::mutex> lock(this->event_queue_mtx);
		this->if_running = false;
	}
	this->cv.notify_all();
	this->cv_event_queue_empty.notify_all();
}

void EventScheduler::waitForAllEventsProcessed()
{
	std::unique_lock<std::mutex> lock(this->event_queue_mtx);
	this->cv_event_queue_empty.wait(lock, [&]() { return this->event_queue.empty(); });
}

EventScheduler event_scheduler;
NAMESPACE_END
